`include "defines.v"

module id_stage(
    input wire                              timer_interrupt_flag_i,

    input wire [`RAM_ADDR_WIDTH - 1 : 0]    inst_addr_i,
    input wire [`INST_WIDTH - 1: 0]         inst_i,

    input wire [11: 0]                      exe_csr_w_addr_i,
    input wire [`REG_BUS]                   exe_csr_w_data_i,
    input wire                              exe_csr_w_ena_i,

    input wire [11: 0]                      mem_csr_w_addr_i,
    input wire [`REG_BUS]                   mem_csr_w_data_i,
    input wire                              mem_csr_w_ena_i,

    input wire [11: 0]                      wb_csr_w_addr_i,
    input wire [`REG_BUS]                   wb_csr_w_data_i,
    input wire                              wb_csr_w_ena_i,

    input wire [`REG_BUS]                   csr_r_data_i,

    output wire                             csr_r_ena_o,
    output wire [11: 0]                     csr_r_addr_o,

    input wire                              exe_mem_load_en_i,

    input wire                              exe_rd_w_ena_i,
    input wire [4 : 0]                      exe_rd_w_addr_i,
    input wire [`REG_BUS]                   exe_rd_w_data_i,

    input wire                              mem_rd_w_ena_i,
    input wire [4 : 0]                      mem_rd_w_addr_i,
    input wire [`REG_BUS]                   mem_rd_w_data_i,

    input wire                              wb_rd_w_ena_i,
    input wire [4 : 0]                      wb_rd_w_addr_i,
    input wire [`REG_BUS]                   wb_rd_w_data_i,

    input wire [`REG_BUS]                   rs1_r_data_i,
    input wire [`REG_BUS]                   rs2_r_data_i,
    
    output wire                             rs1_r_ena_o,
    output wire [4 : 0]                     rs1_r_addr_o,
    output wire                             rs2_r_ena_o,
    output wire [4 : 0]                     rs2_r_addr_o,


    output wire [`RAM_ADDR_WIDTH - 1 : 0]   inst_addr_o,
    output wire [`INST_WIDTH - 1: 0]        inst_o,

    output wire                             rd_w_ena_o,
    output wire [4 : 0]                     rd_w_addr_o,
    output wire                             csr_w_ena_o,
    output wire [11: 0]                     csr_w_addr_o,
    output wire [`REG_BUS]                  op1_o,
    output wire [`REG_BUS]                  op2_o,
    output wire [`REG_BUS]                  op3_o,
    
    output wire[`ALU_SEL_BUS]               alu_sel_o,
    output wire                             alu_sub_flag_o,
    output wire                             alu_word_flag_o,
    output wire                             alu_symbol_flag_o,

    output wire                             transfer_en_o,
    output wire[`TRANSFER_SEL_BUS]          transfer_sel_o,

    output wire                             mem_load_en_o,
    output wire                             mem_store_en_o,
    output wire[`MEM_SEL_BUS]               mem_sel_o,

    // output wire                             csr_en_o,
    output wire[`CSR_SEL_BUS]               csr_sel_o,

    output wire[`RD_SEL_BUS]                rd_sel_o,

    output wire [`REG_BUS]                  exception_type_o,

    output wire                             valid_o,
    output wire                             stall_flag_o
);


    assign inst_addr_o = inst_addr_i;
    assign inst_o      = inst_i;
    
    //exception
    wire exception_type_ecall_flag;
    wire exception_type_mret_flag;
    wire freeze_flag;

    wire [6  : 0]opcode;
    wire [4  : 0]rd;
    wire [2  : 0]funct3;
    wire [4  : 0]rs1;

    wire [4  : 0]rs2;
    // wire [6  : 0]funct7;

    // wire [5  : 0]shamt;

    wire [11: 0]csr_addr;

    assign opcode   = inst_i[6 : 0];
    assign rd       = inst_i[11: 7];
    assign funct3   = inst_i[14:12];
    assign rs1      = inst_i[19:15];

    assign rs2      = inst_i[24:20];
    // assign funct7   = inst_i[31:25];

    // assign shamt    = inst_i[25:20];

    assign csr_addr = inst_i[31:20];
    //imm
    wire [63: 0]imm_i;
    wire [63: 0]imm_s;
    wire [63: 0]imm_b;
    wire [63: 0]imm_u;
    wire [63: 0]imm_j;
    wire [63: 0]imm_csr;

    assign imm_i   = {{52{inst_i[31]}}, inst_i[31:20]};
    assign imm_s   = {{52{inst_i[31]}}, inst_i[31:25] , inst_i[11: 7]};
    assign imm_b   = {{52{inst_i[31]}}, inst_i[ 7], inst_i[30:25] , inst_i[11: 8], 1'b0};
    assign imm_u   = {{32{inst_i[31]}}, inst_i[31:12], 12'h0};
    assign imm_j   = {{43{inst_i[31]}}, inst_i[31], inst_i[19:12], inst_i[20], inst_i[30:21], 1'b0};
    assign imm_csr = {{59{1'b0}}, rs1};
    /**************************************************************************************************************
    ***************************************************************************************************************
        
    ***************************************************************************************************************
    ***************************************************************************************************************/
    // base U-type
    wire inst_lui   =   ~opcode[6] &  opcode[5] &  opcode[4] & ~opcode[3] &  opcode[2];
    wire inst_auipc =   ~opcode[6] & ~opcode[5] &  opcode[4] & ~opcode[3] &  opcode[2];
    
    // base J-type(jump and link)
    wire inst_jal   =    opcode[6] &  opcode[5] & ~opcode[4] &  opcode[3] &  opcode[2];

    // base I-type(jump and link)
    wire inst_jalr  =    opcode[6] &  opcode[5] & ~opcode[4] & ~opcode[3] &  opcode[2];

    // base B-type(branch)
    wire inst_beq   =    opcode[6] &  opcode[5] & ~opcode[4] & ~opcode[3] & ~opcode[2]
                      & ~funct3[2] & ~funct3[1] & ~funct3[0];
    wire inst_bne   =    opcode[6] &  opcode[5] & ~opcode[4] & ~opcode[3] & ~opcode[2]
                      & ~funct3[2] & ~funct3[1] &  funct3[0];
    wire inst_blt   =    opcode[6] &  opcode[5] & ~opcode[4] & ~opcode[3] & ~opcode[2]
                      &  funct3[2] & ~funct3[1] & ~funct3[0];
    wire inst_bge   =    opcode[6] &  opcode[5] & ~opcode[4] & ~opcode[3] & ~opcode[2]
                      &  funct3[2] & ~funct3[1] &  funct3[0];
    wire inst_bltu  =    opcode[6] &  opcode[5] & ~opcode[4] & ~opcode[3] & ~opcode[2]
                      &  funct3[2] &  funct3[1] & ~funct3[0];
    wire inst_bgeu  =    opcode[6] &  opcode[5] & ~opcode[4] & ~opcode[3] & ~opcode[2]
                      &  funct3[2] &  funct3[1] &  funct3[0];

    // base I-type(load)
    wire inst_lb    =   ~opcode[6] & ~opcode[5] & ~opcode[4] & ~opcode[3] & ~opcode[2] &  opcode[1] &  opcode[0]
                      & ~funct3[2] & ~funct3[1] & ~funct3[0];
    wire inst_lh    =   ~opcode[6] & ~opcode[5] & ~opcode[4] & ~opcode[3] & ~opcode[2]
                      & ~funct3[2] & ~funct3[1] &  funct3[0];
    wire inst_lw    =   ~opcode[6] & ~opcode[5] & ~opcode[4] & ~opcode[3] & ~opcode[2]
                      & ~funct3[2] &  funct3[1] & ~funct3[0];
    wire inst_ld   =   ~opcode[6] & ~opcode[5] & ~opcode[4] & ~opcode[3] & ~opcode[2]
                      & ~funct3[2] &  funct3[1] &  funct3[0];
    wire inst_lbu   =   ~opcode[6] & ~opcode[5] & ~opcode[4] & ~opcode[3] & ~opcode[2]
                      &  funct3[2] & ~funct3[1] & ~funct3[0];
    wire inst_lhu   =   ~opcode[6] & ~opcode[5] & ~opcode[4] & ~opcode[3] & ~opcode[2]
                      &  funct3[2] & ~funct3[1] &  funct3[0];
    wire inst_lwu   =   ~opcode[6] & ~opcode[5] & ~opcode[4] & ~opcode[3] & ~opcode[2]
                      &  funct3[2] &  funct3[1] & ~funct3[0];
    // base S-type(store)
    wire inst_sb    =   ~opcode[6] &  opcode[5] & ~opcode[4] & ~opcode[3] & ~opcode[2]
                      & ~funct3[2] & ~funct3[1] & ~funct3[0];
    wire inst_sh    =   ~opcode[6] &  opcode[5] & ~opcode[4] & ~opcode[3] & ~opcode[2]
                      & ~funct3[2] & ~funct3[1] &  funct3[0];
    wire inst_sw    =   ~opcode[6] &  opcode[5] & ~opcode[4] & ~opcode[3] & ~opcode[2]
                      & ~funct3[2] &  funct3[1] & ~funct3[0];
    wire inst_sd    =   ~opcode[6] &  opcode[5] & ~opcode[4] & ~opcode[3] & ~opcode[2]
                      & ~funct3[2] &  funct3[1] &  funct3[0];
    // base I-type
    wire inst_addi  =   ~opcode[6] & ~opcode[5] &  opcode[4] & ~opcode[3] & ~opcode[2]
                      & ~funct3[2] & ~funct3[1] & ~funct3[0];
    wire inst_slti  =   ~opcode[6] & ~opcode[5] &  opcode[4] & ~opcode[3] & ~opcode[2]
                      & ~funct3[2] &  funct3[1] & ~funct3[0];
    wire inst_sltiu =   ~opcode[6] & ~opcode[5] &  opcode[4] & ~opcode[3] & ~opcode[2]
                      & ~funct3[2] &  funct3[1] &  funct3[0]; 
    wire inst_xori  =   ~opcode[6] & ~opcode[5] &  opcode[4] & ~opcode[3] & ~opcode[2]
                      &  funct3[2] & ~funct3[1] & ~funct3[0];
    wire inst_ori   =   ~opcode[6] & ~opcode[5] &  opcode[4] & ~opcode[3] & ~opcode[2]
                      &  funct3[2] &  funct3[1] & ~funct3[0];
    wire inst_andi  =   ~opcode[6] & ~opcode[5] &  opcode[4] & ~opcode[3] & ~opcode[2]
                      &  funct3[2] &  funct3[1] &  funct3[0];

    wire inst_slli  =   ~opcode[6] & ~opcode[5] &  opcode[4] & ~opcode[3] & ~opcode[2]
                      & ~funct3[2] & ~funct3[1] &  funct3[0];
    wire inst_srli  =   ~opcode[6] & ~opcode[5] &  opcode[4] & ~opcode[3] & ~opcode[2]
                      &  funct3[2] & ~funct3[1] &  funct3[0]
                      & ~inst_i[30];
    wire inst_srai  =   ~opcode[6] & ~opcode[5] &  opcode[4] & ~opcode[3] & ~opcode[2]
                      &  funct3[2] & ~funct3[1] &  funct3[0]
                      &  inst_i[30];
    wire inst_addiw =   ~opcode[6] & ~opcode[5] &  opcode[4] &  opcode[3] & ~opcode[2]
                      & ~funct3[2] & ~funct3[1] & ~funct3[0];
    wire inst_slliw =   ~opcode[6] & ~opcode[5] &  opcode[4] &  opcode[3] & ~opcode[2]
                      & ~funct3[2] & ~funct3[1] &  funct3[0]
                    //   & ~shamt[5];
                      & ~inst_i[25];
    wire inst_srliw =   ~opcode[6] & ~opcode[5] &  opcode[4] &  opcode[3] & ~opcode[2]
                      &  funct3[2] & ~funct3[1] &  funct3[0]
                      & ~inst_i[30]
                    //   & ~shamt[5];
                      & ~inst_i[25];
    wire inst_sraiw =   ~opcode[6] & ~opcode[5] &  opcode[4] &  opcode[3] & ~opcode[2]
                      &  funct3[2] & ~funct3[1] &  funct3[0]
                      &  inst_i[30]
                    //   & ~shamt[5];
                      & ~inst_i[25];

    wire inst_ecall =    opcode[6] &  opcode[5] &  opcode[4] & ~opcode[3] & ~opcode[2]
                      & ~funct3[2] & ~funct3[1] & ~funct3[0]
                      & ~inst_i[31] & ~inst_i[30] & ~inst_i[29] & ~inst_i[28] & ~inst_i[27] & ~inst_i[26] & ~inst_i[25] & ~inst_i[24] & ~inst_i[23] & ~inst_i[22] & ~inst_i[21] & ~inst_i[20];
    wire inst_mret  =    opcode[6] &  opcode[5] &  opcode[4] & ~opcode[3] & ~opcode[2]
                      & ~funct3[2] & ~funct3[1] & ~funct3[0]
                      & ~inst_i[31] & ~inst_i[30] &  inst_i[29] &  inst_i[28] & ~inst_i[27] & ~inst_i[26] & ~inst_i[25] & ~inst_i[24] & ~inst_i[23] & ~inst_i[22] &  inst_i[21] & ~inst_i[20];

    // base R-type
    wire inst_add   =   ~opcode[6] &  opcode[5] &  opcode[4] & ~opcode[3] & ~opcode[2]
                      & ~funct3[2] & ~funct3[1] & ~funct3[0]
                    //   & ~funct7[5];
                      & ~inst_i[30];
    wire inst_sub   =   ~opcode[6] &  opcode[5] &  opcode[4] & ~opcode[3] & ~opcode[2]
                      & ~funct3[2] & ~funct3[1] & ~funct3[0]
                    //   &  funct7[5];
                      &  inst_i[30];
    wire inst_sll   =   ~opcode[6] &  opcode[5] &  opcode[4] & ~opcode[3] & ~opcode[2]
                      & ~funct3[2] & ~funct3[1] &  funct3[0];
    wire inst_slt   =   ~opcode[6] &  opcode[5] &  opcode[4] & ~opcode[3] & ~opcode[2]
                      & ~funct3[2] &  funct3[1] & ~funct3[0];
    wire inst_sltu  =   ~opcode[6] &  opcode[5] &  opcode[4] & ~opcode[3] & ~opcode[2]
                      & ~funct3[2] &  funct3[1] &  funct3[0];
    wire inst_xor   =   ~opcode[6] &  opcode[5] &  opcode[4] & ~opcode[3] & ~opcode[2]
                      &  funct3[2] & ~funct3[1] & ~funct3[0];
    wire inst_srl   =   ~opcode[6] &  opcode[5] &  opcode[4] & ~opcode[3] & ~opcode[2]
                      &  funct3[2] & ~funct3[1] &  funct3[0]
                    //   & ~funct7[5];
                      & ~inst_i[30];
    wire inst_sra   =   ~opcode[6] &  opcode[5] &  opcode[4] & ~opcode[3] & ~opcode[2]
                      &  funct3[2] & ~funct3[1] &  funct3[0]
                    //   &  funct7[5];
                      &  inst_i[30];
    wire inst_or    =   ~opcode[6] &  opcode[5] &  opcode[4] & ~opcode[3] & ~opcode[2]
                      &  funct3[2] &  funct3[1] & ~funct3[0];
    wire inst_and   =   ~opcode[6] &  opcode[5] &  opcode[4] & ~opcode[3] & ~opcode[2]
                      &  funct3[2] &  funct3[1] &  funct3[0];
    wire inst_addw  =   ~opcode[6] &  opcode[5] &  opcode[4] &  opcode[3] & ~opcode[2]
                      & ~funct3[2] & ~funct3[1] & ~funct3[0]
                    //   & ~funct7[5];
                      & ~inst_i[30];
    wire inst_subw  =   ~opcode[6] &  opcode[5] &  opcode[4] &  opcode[3] & ~opcode[2]
                      & ~funct3[2] & ~funct3[1] & ~funct3[0]
                    //   &  funct7[5];
                      &  inst_i[30];
    wire inst_sllw  =   ~opcode[6] &  opcode[5] &  opcode[4] &  opcode[3] & ~opcode[2]
                      & ~funct3[2] & ~funct3[1] &  funct3[0];
    wire inst_srlw  =   ~opcode[6] &  opcode[5] &  opcode[4] &  opcode[3] & ~opcode[2]
                      &  funct3[2] & ~funct3[1] &  funct3[0]
                    //   & ~funct7[5];
                      & ~inst_i[30];
    wire inst_sraw  =   ~opcode[6] &  opcode[5] &  opcode[4] &  opcode[3] & ~opcode[2]
                      &  funct3[2] & ~funct3[1] &  funct3[0]
                    //   &  funct7[5];
                      &  inst_i[30];
    // zicsr
    wire inst_csrrw =    opcode[6] &  opcode[5] &  opcode[4] & ~opcode[3] & ~opcode[2]
                      & ~funct3[2] & ~funct3[1] &  funct3[0];
    wire inst_csrrs =    opcode[6] &  opcode[5] &  opcode[4] & ~opcode[3] & ~opcode[2]
                      & ~funct3[2] &  funct3[1] & ~funct3[0];
    wire inst_csrrc =    opcode[6] &  opcode[5] &  opcode[4] & ~opcode[3] & ~opcode[2]
                      & ~funct3[2] &  funct3[1] &  funct3[0];
    wire inst_csrrwi=    opcode[6] &  opcode[5] &  opcode[4] & ~opcode[3] & ~opcode[2]
                      &  funct3[2] & ~funct3[1] &  funct3[0];
    wire inst_csrrsi=    opcode[6] &  opcode[5] &  opcode[4] & ~opcode[3] & ~opcode[2]
                      &  funct3[2] &  funct3[1] & ~funct3[0];
    wire inst_csrrci=    opcode[6] &  opcode[5] &  opcode[4] & ~opcode[3] & ~opcode[2]
                      &  funct3[2] &  funct3[1] &  funct3[0];

    // wire inst_fence_i = ~opcode[6] & ~opcode[5] & ~opcode[4] &  opcode[3] &  opcode[2]
    //                   & ~funct3[2] & ~funct3[1] &  funct3[0];
    // for print
    wire inst_print = inst_i == 32'h7b;
    /**************************************************************************************************************
    ***************************************************************************************************************
        
    ***************************************************************************************************************
    ***************************************************************************************************************/
    assign valid_o = inst_lui
                   | inst_auipc
                   | inst_jal
                   | inst_jalr
                   | inst_beq
                   | inst_bne
                   | inst_blt
                   | inst_bge
                   | inst_bltu
                   | inst_bgeu

                   | inst_lb
                   | inst_lh
                   | inst_lw
                   | inst_ld
                   | inst_lbu
                   | inst_lhu
                   | inst_lwu
                   | inst_sb
                   | inst_sh
                   | inst_sw
                   | inst_sd

                   | inst_addi
                   | inst_slti
                   | inst_sltiu
                   | inst_xori
                   | inst_ori
                   | inst_andi
                   | inst_slli
                   | inst_srli
                   | inst_srai
                   | inst_addiw
                   | inst_slliw
                   | inst_srliw
                   | inst_sraiw

                   | inst_ecall
                   | inst_mret
                   | inst_csrrw
                   | inst_csrrs
                   | inst_csrrc
                   | inst_csrrwi
                   | inst_csrrsi
                   | inst_csrrci

                   | inst_add
                   | inst_sub
                   | inst_sll
                   | inst_slt
                   | inst_sltu
                   | inst_xor
                   | inst_srl
                   | inst_sra
                   | inst_or
                   | inst_and
                   | inst_addw
                   | inst_subw
                   | inst_sllw
                   | inst_srlw
                   | inst_sraw
                   | inst_print;
    /**************************************************************************************************************
    ***************************************************************************************************************
        
    ***************************************************************************************************************
    ***************************************************************************************************************/
    wire inst_base_i;
    wire inst_base_r;
    wire inst_base_s;
    wire inst_base_b;
    wire inst_base_u;
    wire inst_base_j;
    wire inst_zicsr;
    wire inst_zicsr_r;
    wire inst_zicsr_i;
    // wire inst_ecall_and_pri;

    // assign inst_ecall_and_pri = inst_ecall | inst_mret;

    assign inst_zicsr_r = inst_csrrw  | inst_csrrs  | inst_csrrc;
    assign inst_zicsr_i = inst_csrrwi | inst_csrrsi | inst_csrrci;
    assign inst_zicsr   = inst_zicsr_r | inst_zicsr_i;

    //I-type 除ecall mret
    assign inst_base_i = inst_jalr
                       | inst_lb
                       | inst_lh
                       | inst_lw
                       | inst_ld
                       | inst_lbu
                       | inst_lhu
                       | inst_lwu
                       | inst_addi
                       | inst_slti
                       | inst_sltiu
                       | inst_xori
                       | inst_ori
                       | inst_andi
                       | inst_slli
                       | inst_srli
                       | inst_srai
                       | inst_addiw
                       | inst_slliw
                       | inst_srliw
                       | inst_sraiw ;
    //R-type
    assign inst_base_r = inst_add
                       | inst_sub
                       | inst_sll
                       | inst_slt
                       | inst_sltu
                       | inst_xor
                       | inst_srl
                       | inst_sra
                       | inst_or
                       | inst_and
                       | inst_addw
                       | inst_subw
                       | inst_sllw
                       | inst_srlw
                       | inst_sraw ;
    //S-type
    assign inst_base_s = inst_sb  | inst_sh  | inst_sw  | inst_sd;
    //B-type
    assign inst_base_b = inst_beq | inst_bne | inst_blt | inst_bge | inst_bltu | inst_bgeu;
    //U-type
    assign inst_base_u = inst_lui | inst_auipc;
    //J-type
    assign inst_base_j = inst_jal;



    // inst_base_i
    // inst_base_r
    // inst_base_s
    // inst_base_b
    // inst_base_u
    // inst_base_j
    // inst_zicsr
    // inst_ecall_and_pri
    assign rs1_r_ena_o  = inst_base_i | inst_base_r | inst_base_s | inst_base_b | inst_zicsr;
    assign rs1_r_addr_o = rs1_r_ena_o == 1'b1 ? rs1 : 0;
    assign rs2_r_ena_o  = inst_base_r | inst_base_s | inst_base_b;
    assign rs2_r_addr_o = rs2_r_ena_o == 1'b1 ? rs2 : 0;
    
    assign csr_r_ena_o  = inst_zicsr;
    assign csr_r_addr_o = csr_r_ena_o == 1'b1 ? csr_addr : 12'h0;
    
    assign rd_w_ena_o   = inst_base_i | inst_base_r | inst_base_u | inst_base_j | inst_zicsr;
    assign rd_w_addr_o  = rd_w_ena_o == 1'b1 ? rd  : 0;

    assign csr_w_ena_o  = inst_zicsr;
    assign csr_w_addr_o = csr_w_ena_o == 1'b1 ? csr_addr : 0;

    wire [`REG_BUS]   rs1_r_data_i_real;
    wire [`REG_BUS]   rs2_r_data_i_real;
    assign rs1_r_data_i_real = (rs1_r_addr_o   == 5'h0)                                    ? `ZERO_WORD      :
                               (exe_rd_w_ena_i == 1'b1 && exe_rd_w_addr_i == rs1_r_addr_o) ? exe_rd_w_data_i :
                               (mem_rd_w_ena_i == 1'b1 && mem_rd_w_addr_i == rs1_r_addr_o) ? mem_rd_w_data_i :
                               ( wb_rd_w_ena_i == 1'b1 &&  wb_rd_w_addr_i == rs1_r_addr_o) ? wb_rd_w_data_i  : rs1_r_data_i;
    assign rs2_r_data_i_real = (  rs2_r_addr_o == 5'h0)                                    ? `ZERO_WORD      :
                               (exe_rd_w_ena_i == 1'b1 && exe_rd_w_addr_i == rs2_r_addr_o) ? exe_rd_w_data_i :
                               (mem_rd_w_ena_i == 1'b1 && mem_rd_w_addr_i == rs2_r_addr_o) ? mem_rd_w_data_i :
                               ( wb_rd_w_ena_i == 1'b1 &&  wb_rd_w_addr_i == rs2_r_addr_o) ? wb_rd_w_data_i  : rs2_r_data_i;
    wire [`REG_BUS]   csr_r_data_i_real;
    assign csr_r_data_i_real = (exe_csr_w_ena_i == 1'b1 && exe_csr_w_addr_i == csr_r_addr_o) ? exe_csr_w_data_i :
                               (mem_csr_w_ena_i == 1'b1 && mem_csr_w_addr_i == csr_r_addr_o) ? mem_csr_w_data_i :
                               ( wb_csr_w_ena_i == 1'b1 &&  wb_csr_w_addr_i == csr_r_addr_o) ? wb_csr_w_data_i  : csr_r_data_i;

    assign op1_o = (inst_auipc == 1'b1) ? {{64 - `RAM_ADDR_WIDTH{1'b0}}, inst_addr_i} :
                   (inst_zicsr == 1'b1) ? csr_r_data_i_real :
                   ((inst_base_i | inst_base_r | inst_base_s | inst_base_b) == 1'b1) ? rs1_r_data_i_real : 0;

    assign op2_o = (inst_zicsr_r == 1'b1)                 ? rs1_r_data_i_real :
                   (inst_zicsr_i == 1'b1)                 ? imm_csr :
                   (inst_base_i  == 1'b1)                 ? imm_i : 
                   ((inst_base_r | inst_base_b) == 1'b1)   ? rs2_r_data_i_real :
                   (inst_base_s == 1'b1)                  ? imm_s :
                   (inst_base_u == 1'b1)                  ? imm_u : 0;

    assign op3_o = (inst_base_s == 1'b1) ? rs2_r_data_i_real :
                   (inst_base_b == 1'b1) ? imm_b :
                   (inst_base_j == 1'b1) ? imm_j : 0;

    /**************************************************************************************************************
    ***************************************************************************************************************
        ALU_SEL
    ***************************************************************************************************************
    ***************************************************************************************************************/

    // 不需要alu
    // inst_beq    
    // inst_bne    
    // inst_ecall  
    // inst_mret   
    // inst_csrrw  
    // inst_csrrwi 
    wire                alu_add_flag;
    wire                alu_slt_flag;
    wire                alu_or_flag;
    wire                alu_and_flag;
    wire                alu_xor_flag;
    wire                alu_sll_flag;
    wire                alu_srl_flag;
    wire                alu_sra_flag;

    assign alu_add_flag = inst_lui
                        | inst_auipc
                        | inst_jalr
                        | inst_lb
                        | inst_lh
                        | inst_lw
                        | inst_ld
                        | inst_lbu
                        | inst_lhu
                        | inst_lwu
                        | inst_sb
                        | inst_sh
                        | inst_sw
                        | inst_sd
                        | inst_add
                        | inst_addi
                        | inst_sub
                        | inst_addw
                        | inst_addiw
                        | inst_subw;

    assign alu_slt_flag = inst_blt
                        | inst_bge
                        | inst_bltu
                        | inst_bgeu
                        | inst_slt
                        | inst_slti
                        | inst_sltu
                        | inst_sltiu;

    assign alu_and_flag = inst_and
                        | inst_andi
                        | inst_csrrc
                        | inst_csrrci;

    assign alu_or_flag  = inst_or
                        | inst_ori
                        | inst_csrrs
                        | inst_csrrsi;

    assign alu_xor_flag = inst_xor
                        | inst_xori;

    assign alu_sll_flag = inst_sll
                        | inst_slli
                        | inst_sllw
                        | inst_slliw;

    assign alu_srl_flag = inst_srl
                        | inst_srli
                        | inst_srlw
                        | inst_srliw;

    assign alu_sra_flag = inst_sra
                        | inst_srai
                        | inst_sraw
                        | inst_sraiw;

    wire                alu_en;

    assign alu_sub_flag_o = inst_sub
                          | inst_subw
                          | alu_slt_flag;
    assign alu_word_flag_o = inst_addw
                           | inst_addiw
                           | inst_subw
                           | inst_sllw
                           | inst_slliw
                           | inst_srlw
                           | inst_srliw
                           | inst_sraw
                           | inst_sraiw;
    assign alu_symbol_flag_o = inst_slt | inst_slti | inst_blt | inst_bge;

    assign alu_en = alu_add_flag
                  | alu_slt_flag
                  | alu_or_flag 
                  | alu_and_flag
                  | alu_xor_flag
                  | alu_sll_flag
                  | alu_srl_flag
                  | alu_sra_flag;
    assign alu_sel_o = {`ALU_SEL_WIDTH{alu_add_flag}} & `ALU_SEL_ADD
                     | {`ALU_SEL_WIDTH{alu_slt_flag}} & `ALU_SEL_SLT
                     | {`ALU_SEL_WIDTH{alu_or_flag }} & `ALU_SEL_OR
                     | {`ALU_SEL_WIDTH{alu_and_flag}} & `ALU_SEL_AND
                     | {`ALU_SEL_WIDTH{alu_xor_flag}} & `ALU_SEL_XOR
                     | {`ALU_SEL_WIDTH{alu_sll_flag}} & `ALU_SEL_SLL
                     | {`ALU_SEL_WIDTH{alu_srl_flag}} & `ALU_SEL_SRL
                     | {`ALU_SEL_WIDTH{alu_sra_flag}} & `ALU_SEL_SRA ;

    /**************************************************************************************************************
    ***************************************************************************************************************
        TRANSFER_SEL
    ***************************************************************************************************************
    ***************************************************************************************************************/
    assign transfer_en_o = inst_jal | inst_jalr | inst_beq | inst_bne | inst_blt | inst_bge | inst_bltu| inst_bgeu;
    assign transfer_sel_o = {`TRANSFER_SEL_WIDTH{inst_jal }} & `TRANSFER_JAL 
                          | {`TRANSFER_SEL_WIDTH{inst_jalr}} & `TRANSFER_JALR
                          | {`TRANSFER_SEL_WIDTH{inst_beq }} & `TRANSFER_BEQ 
                          | {`TRANSFER_SEL_WIDTH{inst_bne }} & `TRANSFER_BNE 
                          | {`TRANSFER_SEL_WIDTH{inst_blt }} & `TRANSFER_BLT 
                          | {`TRANSFER_SEL_WIDTH{inst_bge }} & `TRANSFER_BGE 
                          | {`TRANSFER_SEL_WIDTH{inst_bltu}} & `TRANSFER_BLTU
                          | {`TRANSFER_SEL_WIDTH{inst_bgeu}} & `TRANSFER_BGEU ;

    /**************************************************************************************************************
    ***************************************************************************************************************
        MEM_SEL
    ***************************************************************************************************************
    ***************************************************************************************************************/

    assign mem_load_en_o  = inst_lb | inst_lh | inst_lw | inst_ld | inst_lbu | inst_lhu | inst_lwu;
    assign mem_store_en_o = inst_sb | inst_sh | inst_sw | inst_sd;
    assign mem_sel_o      = {`MEM_SEL_WIDTH{inst_lb }} & `MEM_LB
                          | {`MEM_SEL_WIDTH{inst_lh }} & `MEM_LH
                          | {`MEM_SEL_WIDTH{inst_lw }} & `MEM_LW
                          | {`MEM_SEL_WIDTH{inst_ld }} & `MEM_LD
                          | {`MEM_SEL_WIDTH{inst_lbu}} & `MEM_LBU
                          | {`MEM_SEL_WIDTH{inst_lhu}} & `MEM_LHU
                          | {`MEM_SEL_WIDTH{inst_lwu}} & `MEM_LWU
                          | {`MEM_SEL_WIDTH{inst_sb }} & `MEM_SB
                          | {`MEM_SEL_WIDTH{inst_sh }} & `MEM_SH
                          | {`MEM_SEL_WIDTH{inst_sw }} & `MEM_SW
                          | {`MEM_SEL_WIDTH{inst_sd }} & `MEM_SD ;
    /**************************************************************************************************************
    ***************************************************************************************************************
        CSR_SEL
    ***************************************************************************************************************
    ***************************************************************************************************************/
    // assign csr_en_o  = inst_zicsr;
    assign csr_sel_o = {`CSR_SEL_WIDTH{inst_csrrw | inst_csrrwi}} & `CSR_CSRRW
                     | {`CSR_SEL_WIDTH{inst_csrrs | inst_csrrsi}} & `CSR_CSRRS
                     | {`CSR_SEL_WIDTH{inst_csrrc | inst_csrrci}} & `CSR_CSRRC ;
    /**************************************************************************************************************
    ***************************************************************************************************************
        rd_sel
    ***************************************************************************************************************
    ***************************************************************************************************************/    
    assign rd_sel_o = {`RD_SEL_WIDTH{alu_en              }} & `RD_SEL_ALU 
                    | {`RD_SEL_WIDTH{inst_jal | inst_jalr}} & `RD_SEL_LINK
                    | {`RD_SEL_WIDTH{inst_zicsr          }} & `RD_SEL_CSR 
                    | {`RD_SEL_WIDTH{mem_load_en_o       }} & `RD_SEL_LOAD ;
    /**************************************************************************************************************
    ***************************************************************************************************************
        load相关
    ***************************************************************************************************************
    ***************************************************************************************************************/
    wire pre_inst_is_load;
    
    wire stall_flag_for_reg1_loadrelate;
    wire stall_flag_for_reg2_loadrelate;
    
    assign pre_inst_is_load = (exe_mem_load_en_i == 1'b1) ? 1'b1 : 1'b0;  
    assign stall_flag_for_reg1_loadrelate = (rs1_r_ena_o == 1'h1) && (pre_inst_is_load == 1'b1) && (exe_rd_w_addr_i == rs1_r_addr_o) ? 1'h1 : 1'h0;
    assign stall_flag_for_reg2_loadrelate = (rs2_r_ena_o == 1'h1) && (pre_inst_is_load == 1'b1) && (exe_rd_w_addr_i == rs2_r_addr_o) ? 1'h1 : 1'h0;

    assign stall_flag_o = freeze_flag == 1'b1 ? 1'b0 : stall_flag_for_reg1_loadrelate | stall_flag_for_reg2_loadrelate;
    /**************************************************************************************************************
    ***************************************************************************************************************
        exception
    ***************************************************************************************************************
    ***************************************************************************************************************/
    //exception flag

    assign exception_type_ecall_flag = inst_ecall;
    assign exception_type_mret_flag  = inst_mret;

    //[ 5]   : ecall
    //[39]   : timer_interrupt
    //[63]   : mret
    assign exception_type_o = valid_o == 1'b1 ? {exception_type_mret_flag, 23'h0, timer_interrupt_flag_i, 33'h0, exception_type_ecall_flag, 5'h0} : `ZERO_WORD;

    assign freeze_flag = exception_type_o == `ZERO_WORD ? 1'b0 : 1'b1;
endmodule
